using Godot;
using System;
using System.Diagnostics;

public partial class PlayerController : CharacterBody2D, IGravityTarget
{

    #region 移动
    [Export] public bool EnableMovement = true;
    [ExportGroup("Movement Stats")]
    [Export] public float MoveSpeed = 300.0f;
    [Export] public float Acceleration = 1800.0f; // 地面起步加速度
    [Export] public float Friction = 2000.0f;     // 地面停车摩擦力
    [Export] public float AirAcceleration = 1200.0f; // 空中变向加速度

    [ExportGroup("Jump Stats")]
    [Export] public float JumpHeight = 120.0f;    //以此像素为单位的跳跃高度
    [Export] public float JumpTimeToPeak = 0.4f;  // 跳到最高点需要多少秒
    [Export] public float JumpTimeToDescent = 0.3f; // 下落需要多少秒（比上升短意味着下落更快，手感更沉稳）

    [ExportGroup("Assists")]
    [Export] public float CoyoteTime = 0.1f;      // 土狼时间窗口
    [Export] public float JumpBufferTime = 0.1f;  // 预输入窗口


    // 外部重力接管标志位
    [ExportGroup("Gravity")]
    [Export] private bool _isGravityOverridden = false;
    [Export] private Vector2 _externalVelocityOverride;



    [ExportGroup("Interaction")]
    [Export] public float PushForce = 50.0f; // 推力大小，建议从 50-100 开始调
    [Export] public float PushCooldown = 0.1f;
    [Export] private float PushCooldownTimer = 0.0f;

    [ExportGroup("Animation")]
    [Export] public Node2D VisualRoot;

    [Export] public Vector2 JumpSquashScale = new Vector2(0.8f, 1.2f); // 跳跃时的挤压拉伸比例
    [Export] public Vector2 LandSquashScale = new Vector2(1.2f, 0.8f); // 落地时的挤压拉伸比例



    [ExportGroup("Effects")]
    [Export] public GpuParticles2D RunParticles;
    [Export] public GpuParticles2D JumpParticles;
    [Export] public GpuParticles2D LandParticles;
    [Export] public GpuParticles2D SwitchParticles;


    private bool _wasOnFloor;
    private Tween _scaleTween;


    // 内部计算出的重力和跳跃力度
    private float _jumpVelocity;
    private float _jumpGravity;
    private float _fallGravity;

    // 计时器
    private double _coyoteTimer = 0;
    private double _jumpBufferTimer = 0;


    public void MoveLogic(double delta)
    {
        float dt = (float)delta;
        Vector2 velocity = Velocity;

        // --- 1. 处理计时器 ---
        // 土狼时间：如果在地面，重置计时器；如果在空中，倒计时
        if (IsOnFloor())
        {
            _coyoteTimer = CoyoteTime;
        }
        else
        {
            _coyoteTimer -= dt;
        }

        // 跳跃预输入：如果按了跳跃，设置计时器；否则倒计时
        if (Input.IsActionJustPressed("jump"))
        {
            _jumpBufferTimer = JumpBufferTime;
        }
        else
        {
            _jumpBufferTimer -= dt;
        }

        // --- 2. 处理重力 ---
        // 根据是在上升还是下降，应用不同的重力（下落更快=手感更好）
        if (velocity.Y < 0) // 上升中
        {
            velocity.Y += _jumpGravity * dt;
        }
        else // 下落中
        {
            velocity.Y += _fallGravity * dt;
        }

        // --- 3. 处理跳跃逻辑 ---
        // 只有当：预输入有效 且 (在地面 或 土狼时间有效) 时，才起跳
        if (_jumpBufferTimer > 0 && _coyoteTimer > 0)
        {

            ApplySquashStretch(JumpSquashScale); // 执行挤压拉伸动画
            PlayJumpParticles();                 // 播放跳跃粒子


            velocity.Y = _jumpVelocity;
            _jumpBufferTimer = 0; // 消耗掉预输入
            _coyoteTimer = 0;     // 消耗掉土狼时间（防止连跳）
        }

        // 可变跳跃高度：如果玩家松开了跳跃键，且当前正在上升，瞬间削减垂直速度
        if (Input.IsActionJustReleased("jump") && velocity.Y < 0)
        {
            // 这种写法会让跳跃瞬间被“截断”，实现轻按跳得低
            velocity.Y *= 0.5f;
        }

        // --- 4. 处理水平移动 ---
        float direction = Input.GetAxis("move_left", "move_right");

        if (direction != 0)
        {
            // 有输入时：应用加速度
            // 如果在空中，加速度可能会不同
            float accel = IsOnFloor() ? Acceleration : AirAcceleration;
            velocity.X = Mathf.MoveToward(velocity.X, direction * MoveSpeed, accel * dt);
        }
        else
        {
            // 无输入时：应用摩擦力（减速）
            // 空中摩擦力通常设得很小，或者直接用 AirAcceleration 减速
            float fric = IsOnFloor() ? Friction : AirAcceleration;
            velocity.X = Mathf.MoveToward(velocity.X, 0, fric * dt);
        }

        Velocity = velocity;
        MoveAndSlide();


        // animation
        // 检测落地
        if (!_wasOnFloor && IsOnFloor())
        {
            // 变扁平 (X变大, Y变小)
            ApplySquashStretch(LandSquashScale, 0.1f);

            PlayLandParticles();
        }
        _wasOnFloor = IsOnFloor();


        // 处理与刚体的碰撞推力

        // 2. 移动完立刻检查撞到了谁
        if (PushCooldownTimer > 0)
        {
            PushCooldownTimer -= dt;
            return;
        }
        PushCooldownTimer = PushCooldown;
        for (int i = 0; i < GetSlideCollisionCount(); i++)
        {
            var collision = GetSlideCollision(i);

            // 看看是不是刚体 (ChromaBox)
            if (collision.GetCollider() is RigidBody2D box)
            {
                // 添加调试信息：看看这一行有没有打印出来！
                GD.Print("撞到了刚体: " + box.Name);

                // 施加推力
                Vector2 pushDir = -collision.GetNormal();
                pushDir.Y = 0; // 只允许水平推，防止站在箱子上把它踩下去

                // 这里的 PushForce 设大一点试试，比如 300 或 500
                box.ApplyCentralImpulse(pushDir * PushForce);
            }
        }


    }

    public override void _Ready()
    {




        // 通过高度和时间反向计算物理公式，这样调整参数更直观
        _jumpVelocity = (2.0f * JumpHeight) / JumpTimeToPeak * -1.0f;
        _jumpGravity = (2.0f * JumpHeight) / (JumpTimeToPeak * JumpTimeToPeak);
        _fallGravity = (2.0f * JumpHeight) / (JumpTimeToDescent * JumpTimeToDescent);



        // ---
        base._Ready();
        UpdateCollisionMask();
        UpdateParticleColor(); // 初始化颜色



        // --- v0.2新增：寻找起点并瞬移 ---
        // 获取当前场景树中第一个属于 "LevelStart" 组的节点
        var startPoint = GetTree().GetFirstNodeInGroup("LevelStart") as Node2D;

        if (startPoint != null)
        {
            GlobalPosition = startPoint.GlobalPosition;
            // 如果你需要重置速度
            Velocity = Vector2.Zero;
        }
        else
        {
            GD.Print("警告: 这个关卡没有 LevelStart，玩家将出现在默认位置。");
        }


        // 启用处理
        SetProcess(true);
        SetPhysicsProcess(true);
    }
    #endregion
    #region 物理update



    #endregion


    #region 颜色切换var
    // [Export] public PlayerColor Cfg.CurPlayerColor = PlayerColor.Red;
    [Export] public ColorRect PlayerBody = null;
    [Export] public float SwitchCooldown = 0.5f;


    // 物理层掩码 (对应 Project Settings 的数值)
    // 1=World, 2=Red, 4=Blue (二进制位) -> Godot的 layer value 1, 2, 3
    private const uint MASK_WORLD = 1;
    private const uint MASK_RED_OBJ = 2;
    private const uint MASK_BLUE_OBJ = 4;
    private const uint MASK_GREEN_OBJ = 8;

    // public override void _Ready()
    // {

    // }

    // 供外部调用（比如穿过传送门时）
    public void SwitchColor()// switch to next color
    {
        Cfg.CurPlayerColor = Cfg.NextColor(Cfg.CurPlayerColor);
        UpdateCollisionMask();
        PlayerBody.Modulate = Cfg.GetColorValue(Cfg.CurPlayerColor);
        PlaySwitchParticles();
        UpdateParticleColor();

        // sfx
        AudioManager.Instance.PlaySfx("res://assets/my_sfx/change_color.wav", -5f, 0.2f);

    }

    public void SwitchColor(PlayerColor newColor) // switch to specified color
    {
        Cfg.CurPlayerColor = newColor;
        UpdateCollisionMask();
        PlayerBody.Modulate = Cfg.GetColorValue(newColor);

        PlaySwitchParticles();
        UpdateParticleColor();
        // sfx
        AudioManager.Instance.PlaySfx("res://assets/my_sfx/change_color.wav", -5f, 0.2f);
    }

    public PlayerColor GetCurrentColor()
    {
        return Cfg.CurPlayerColor;
    }

    public PlayerColor GetNextColor()
    {
        return Cfg.NextColor(Cfg.CurPlayerColor);
    }

    // 供外部组件（重力垫）调用：获取当前速度
    public Vector2 GetVelocity()
    {
        return Velocity; // CharacterBody2D 自带 Velocity
    }

    // 供外部组件（重力垫）调用：开启/关闭重力接管
    public void AddExternalVelocity(Vector2 force, double delta)
    {
        // 将力累加到当前的 Velocity 上
        // 这里的 force 其实是 加速度 (Acceleration)
        Velocity += force * (float)delta;
    }

    // 供外部组件调用：每帧设置强制速度
    public void ApplyExternalVelocity(Vector2 newVel)
    {
        if (_isGravityOverridden)
        {
            Velocity = newVel;
        }
    }


    public void UpdateCollisionMask()
    {
        // 1. 重置所有碰撞检测
        CollisionMask = 0;

        // 2. 永远开启 Layer 1 (World/普通地形)
        // 参数1：层级索引 (1-based)，即 Layer 1
        // 参数2：是否开启
        SetCollisionMaskValue(1, true);

        // 3. 根据颜色开启对应的层级
        if (Cfg.CurPlayerColor == PlayerColor.Red)
        {
            SetCollisionMaskValue(2, true);
            SetCollisionMaskValue(3, false);
            SetCollisionMaskValue(4, false);
        }
        else if (Cfg.CurPlayerColor == PlayerColor.Blue)
        {
            SetCollisionMaskValue(3, true);
            SetCollisionMaskValue(2, false);
            SetCollisionMaskValue(4, false);
        }
        else if (Cfg.CurPlayerColor == PlayerColor.Green)
        {
            SetCollisionMaskValue(4, true);
            SetCollisionMaskValue(2, false);
            SetCollisionMaskValue(3, false);
        }
        Modulate = Cfg.GetColorValue(Cfg.CurPlayerColor);
    }

    public override void _Process(double delta)
    {

        Debug();


        // animation update
    }
    public override void _PhysicsProcess(double delta)
    {
        if (EnableMovement)
            MoveLogic(delta);
        // --- 粒子特效逻辑 ---
        HandleParticleEffects();
    }

    #endregion
    #region  动画

    // 辅助方法：执行挤压拉伸
    // scale: 目标缩放，比如 (1.2, 0.8) 变扁
    // duration: 持续时间
    private void ApplySquashStretch(Vector2 targetScale, float duration = 0.1f)
    {
        // 杀掉旧动画，防止冲突
        if (_scaleTween != null && _scaleTween.IsRunning()) _scaleTween.Kill();

        _scaleTween = CreateTween();
        _scaleTween.SetTrans(Tween.TransitionType.Sine);
        _scaleTween.SetEase(Tween.EaseType.Out);

        // 1. 变形成目标形状
        _scaleTween.TweenProperty(VisualRoot, "scale", targetScale, duration);
        // 2. 弹回原始形状 (1, 1)
        _scaleTween.TweenProperty(VisualRoot, "scale", Vector2.One, duration);
    }


    #endregion


    #region 粒子特效
    public void UpdateParticleColor()
    {
        Color targetColor = Cfg.GetColorValue(Cfg.CurPlayerColor);
        // 让粒子稍微亮一点 (HDR效果)
        // targetColor *= 1.5f;

        RunParticles.Modulate = targetColor;
        JumpParticles.Modulate = targetColor;
        LandParticles.Modulate = targetColor;
        SwitchParticles.Modulate = targetColor;
    }



    public void PlaySwitchParticles()
    {
        //播放变色爆发粒子
        SwitchParticles.Restart();
        SwitchParticles.Emitting = true;
    }



    public void PlayLandParticles()
    {
        // 播放落地尘土粒子
        LandParticles.Restart();
        LandParticles.Emitting = true;
    }

    public void PlayJumpParticles()
    {
        // 播放跳跃粒子
        JumpParticles.Restart();
        JumpParticles.Emitting = true;
    }


    public void HandleParticleEffects()
    {
        // 跑步粒子 (持续性)
        if (IsOnFloor() && Mathf.Abs(Velocity.X) > 10.0f)
        {
            RunParticles.Emitting = true;

        }
        else
        {
            RunParticles.Emitting = false;
        }
    }


    #endregion


    #region  Die!

    public void Die()
    {
        // 禁用玩家控制
        SetProcess(false);
        SetPhysicsProcess(false);

        // 归零速度
        Velocity = Vector2.Zero;


        //重新加载当前场景
        CallDeferred(nameof(ReloadCurrentScene));
    }
    #endregion


    private void ReloadCurrentScene()
    {
        SceneTransition.Instance.ReloadCurrentScene();
    }


    #region 外部停止移动


    public void SetControl(bool enabled)
    {
        SetProcess(enabled);
        SetPhysicsProcess(enabled);
    }
    #endregion








    #region Debug
    private void Debug()
    {
        // // //如果按下 R 键
        // if (Input.IsActionJustPressed("debug_q"))
        // {
        //     SwitchColor();
        //     return;
        // }


        // if (Input.IsActionJustPressed("debug_p"))
        // {
        //     
        //     // 传送到终点
        //     var exitPoint = GetTree().GetFirstNodeInGroup("LevelExit") as Node2D;
        //     if (exitPoint != null)
        //     {
        //         GD.Print("传送到终点");
        //         GlobalPosition = exitPoint.GlobalPosition;
        //     }
        //     else
        //     {
        //         GD.Print("警告: 这个关卡没有 LevelExit，无法传送。");
        //     }
        //     return;
        // }


        // if (Input.IsActionJustPressed("debug_l"))
        // {
        //     GameState.DoorIsOpen = !GameState.DoorIsOpen;
        //     GD.Print("切换门状态: " + (GameState.DoorIsOpen ? "开" : "关"));
        // }
        // if (Input.IsActionJustPressed("restart"))
        // {
        //     Die();
        // }
    }
    #endregion
}